{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 感知机\n",
    "- 感知机接受多个信号，输出一个信号；感知机的信号只有 1（“传递信号”） 和 0（“不传递信号 ”） 两种取值\n",
    "- 权重是控制输入信号的重要性的参数，偏置是调整神经元被激活的容易程度的参数\n",
    "- 信号乘以权重并加上偏置，其值超过阈值(`linear threshold unit (LTU)`\n",
    ")，神经元即激活:    \n",
    "    - $z=w_1x_1+w_2x_2+...w_nx_n=W^T\\cdot X$   \n",
    "    - $h_w(X)=step(z)$\n",
    "    \n",
    "$$step(z)=\\begin{cases}0\\quad &if\\ z<0\\\\1\\quad &if\\ z\\geq0\\end{cases}\\qquad or\\qquad sgn(z)=\\begin{cases}-1\\quad &if\\ z<0\\\\0\\quad &if\\ z=0\\\\+1\\quad &if\\ z>0\\end{cases}$$\n",
    "    \n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0, 0, 0, 1)"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 与门\n",
    "def AND(x1, x2):\n",
    "    w1, w2, theta = 0.5, 0.5, 0.7\n",
    "    tmp = w1 * x1 + w2 * x2\n",
    "    return 0 if tmp <= theta else 1\n",
    "\n",
    "\n",
    "AND(0, 0), AND(0, 1), AND(1, 0), AND(1, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "def AND(x1, x2):\n",
    "    x = np.array([x1, x2])\n",
    "    w = np.array([0.5, 0.5])\n",
    "    b = -0.7\n",
    "    temp = np.sum(w * x) + b\n",
    "    return 0 if temp <= 0 else 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 非门\n",
    "def NAND(x1, x2):\n",
    "    x = np.array([x1, x2])\n",
    "    w = np.array([-0.5, -0.5])\n",
    "    b = 0.7\n",
    "    tmp = np.sum(w * x) + b\n",
    "    return 0 if tmp <= 0 else 1\n",
    "\n",
    "\n",
    "NAND(0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 或门\n",
    "def OR(x1, x2):\n",
    "    x = np.array([x1, x2])\n",
    "    w = np.array([0.5, 0.5])\n",
    "    b = -0.2\n",
    "    tmp = np.sum(w * x) + b\n",
    "    return 0 if tmp <= 0 else 1\n",
    "\n",
    "\n",
    "OR(0, 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 单层感知机只能表示线性空间，因此无法表示异或门(XOR)\n",
    "- 二层感知机，激活函数为非线性的`sigmoid` 函数时，可以表示任意函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0, 1, 0, 1)"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 多层感知机 表示 XOR：\n",
    "def XOR(x1, x2):\n",
    "    s1 = NAND(x1, x2)\n",
    "    s2 = OR(x1, x2)\n",
    "    y = AND(s1, s2)\n",
    "    return y\n",
    "\n",
    "\n",
    "XOR(0, 0), XOR(0, 1), XOR(1, 1), XOR(1, 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 神经网络\n",
    "- 神经网络的一个重要性质就是自动的从数据中学习到合适的权重参数；\n",
    "- 权重用于控制各个信号的重要性，偏置表示神经元被激活的容易程度。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ***激活函数***"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "%matplotlib notebook"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 阶跃函数\n",
    "def step_function(x):\n",
    "    y = x > 0\n",
    "    return y.astype(np.int)\n",
    "#     return np.array(x>0, type=np.int)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "# sigmoid 函数\n",
    "def sigmoid(x):\n",
    "    return 1 / (1 + np.exp(-x))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "# ReLU（Rectified Linear Unit） 函数\n",
    "def relu(x):\n",
    "    return np.maximum(0, x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x7f7fcab4f410>"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "x = np.arange(-5.0, 5.0, 0.1)\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "for func in [step_function, sigmoid, relu]:\n",
    "    y = func(x)\n",
    "    ax.plot(x, y, label=func.__name__)\n",
    "    ax.set_ylim([min(y) - 0.1, max(y) + 0.1])\n",
    "ax.legend(loc=\"center left\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.88175789, -1.37942033,  0.07669233,  1.59580791],\n",
       "       [-0.69581179,  0.50923301,  1.59635868, -0.63803481],\n",
       "       [-1.31170516, -0.8287045 ,  0.46636644,  2.00029271],\n",
       "       [ 0.48414047, -0.02164478,  0.33609554, -1.32446495],\n",
       "       [ 1.0547773 , -0.06546479,  1.20240108,  1.34639088]])"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.random.randn(5, 4)\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.        , 0.        , 0.07669233, 1.59580791],\n",
       "       [0.        , 0.50923301, 1.59635868, 0.        ],\n",
       "       [0.        , 0.        , 0.46636644, 2.00029271],\n",
       "       [0.48414047, 0.        , 0.33609554, 0.        ],\n",
       "       [1.0547773 , 0.        , 1.20240108, 1.34639088]])"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "relu(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "def sigmoid(z):\n",
    "    A = 1 / (1 + np.exp(-z))\n",
    "    return (A, z)\n",
    "\n",
    "\n",
    "def tanh(z):\n",
    "    A = np.tanh(z)\n",
    "    return (A, z)\n",
    "\n",
    "\n",
    "def relu(z):\n",
    "    A = np.maximum(0, z)\n",
    "    return (A, z)\n",
    "\n",
    "\n",
    "def leaky_relu(z):\n",
    "    A = np.maximum(0.1 * z, z)\n",
    "    return (A, z)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 864x576 with 4 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "z = np.linspace(-10, 10, 100)\n",
    "A_sigmoid, z = sigmoid(z)\n",
    "A_tanh, z = tanh(z)\n",
    "A_relu, z = relu(z)\n",
    "A_leaky_relu, z = leaky_relu(z)\n",
    "\n",
    "plt.figure(figsize=(12, 8))\n",
    "plt.subplot(2, 2, 1)\n",
    "plt.plot(z, A_sigmoid, label='Function')\n",
    "plt.plot(z, A_sigmoid * (1 - A_sigmoid), label='Derivative')\n",
    "plt.legend(loc='upper left')\n",
    "plt.xlabel('z')\n",
    "plt.ylabel(r'$\\frac{1}{1+e^{-z}}$')\n",
    "plt.title('Sigmoid Function', fontsize=16)\n",
    "\n",
    "plt.subplot(2, 2, 2)\n",
    "plt.plot(z, A_tanh, 'b', label=\"Function\")\n",
    "plt.plot(z, 1 - np.square(A_tanh), 'r', label=\"Derivative\")\n",
    "plt.legend(loc=\"upper left\")\n",
    "plt.xlabel(\"z\")\n",
    "plt.ylabel(r\"$\\frac{e^z - e^{-z}}{e^z + e^{-z}}$\")\n",
    "plt.title(\"Hyperbolic Tangent Function\", fontsize=16)\n",
    "\n",
    "plt.subplot(2, 2, 3)\n",
    "plt.plot(z, A_relu, 'g')\n",
    "plt.xlabel(\"z\")\n",
    "plt.ylabel(r\"$max\\{0, z\\}$\")\n",
    "plt.title(\"ReLU Function\", fontsize=16)\n",
    "\n",
    "plt.subplot(2, 2, 4)\n",
    "plt.plot(z, A_leaky_relu, 'y')\n",
    "plt.xlabel(\"z\")\n",
    "plt.ylabel(r\"$max\\{0.1z, z\\}$\")\n",
    "plt.title(\"Leaky ReLU Function\", fontsize=16)\n",
    "plt.tight_layout()\n",
    "plt.show();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `sigmoid` 函数是平滑的曲线，阶跃函数则以 0 为界，发生急剧变化\n",
    "- 感知机中流动的是 0 或 1 的二元信号，神经网络中流动的则是连续的实值信号\n",
    "- 输入值越大，输入信号为重要信息时，两者都会输出较大值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ***输出层的设计***"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 回归问题用恒等函数  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "def identity_function(x):\n",
    "    return x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 分类问题用 softmax 函数\n",
    "$$y_k=\\frac{exp(a_k)}{\\sum_{i=1}^n exp(a_{i})}$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "def softmax(x):\n",
    "    if x.ndim == 2:\n",
    "        x = x.T  # 转置是因为数组的广播规则\n",
    "        x = x - np.max(x, axis=0)\n",
    "        y = np.exp(x) / np.sum(np.exp(x), axis=0)\n",
    "        return y.T\n",
    "\n",
    "    x = x - np.max(x)  # 溢出对策\n",
    "    return np.exp(x) / np.sum(np.exp(x))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([0.68997448, 0.50499983, 0.59868766]),\n",
       " array([0.46976453, 0.21534289, 0.31489258]))"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.array([0.8,0.02,0.4])\n",
    "sigmoid(x), softmax(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ***简单的三层神经网络***"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "def init_network():\n",
    "    network = {}\n",
    "    network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])\n",
    "    network['b1'] = np.array([0.1, 0.2, 0.3])\n",
    "    network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])\n",
    "    network['b2'] = np.array([0.1, 0.2])\n",
    "    network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])\n",
    "    network['b3'] = np.array([0.1, 0.2])\n",
    "    return network"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 神经网络的推理处理，即前向传播(forward propagation)\n",
    "def forword(network, x):\n",
    "    W1, W2, W3 = network['W1'], network['W2'], network['W3']\n",
    "    b1, b2, b3 = network['b1'], network['b2'], network['b3']\n",
    "    \n",
    "    a1 = np.dot(x, W1) + b1\n",
    "    z1 = sigmoid(a1)\n",
    "    a2 = np.dot(z1, W2) + b2\n",
    "    z2 = sigmoid(a2)\n",
    "    a3 = np.dot(z2, W3) + b3\n",
    "    y = identity_function(a3)\n",
    "    \n",
    "    return y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.31682708 0.69627909]\n"
     ]
    }
   ],
   "source": [
    "network = init_network()\n",
    "x = np.array([1.0, 0.5])\n",
    "y = forword(network, x)\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ***手写字识别***"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "导入数据集，确认数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os, sys\n",
    "sys.path.append(os.pardir)\n",
    "from dataset.mnist import load_mnist\n",
    "import pickle"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "(x_train, t_train), (x_test, y_test) = load_mnist(flatten=True, normalize=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(60000, 784) (60000,) (10000, 784)\n"
     ]
    }
   ],
   "source": [
    "print(x_train.shape,t_train.shape, x_test.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "from PIL import Image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "def img_show(img):\n",
    "    pil_image = Image.fromarray(np.uint8(img))\n",
    "    pil_image.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5\n"
     ]
    }
   ],
   "source": [
    "img = x_train[0]\n",
    "label = t_train[0]\n",
    "print(label)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "img = img.reshape(28, 28)\n",
    "img_show(img)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "神经网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_data():\n",
    "    (x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, \n",
    "                                                      normalize=True,\n",
    "                                                     one_hot_label=False)\n",
    "    return x_test, t_test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "def init_network():\n",
    "    with open('dataset/sample_weight.pkl', 'rb') as f:\n",
    "        network = pickle.load(f)\n",
    "    return network"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "def predict(network, x):\n",
    "    W1, W2, W3 = network['W1'], network['W2'], network['W3']\n",
    "    b1, b2, b3 = network['b1'], network['b2'], network['b3']\n",
    "    \n",
    "    a1 = np.dot(x, W1) + b1\n",
    "    z1 = sigmoid(a1)\n",
    "    a2 = np.dot(z1, W2) + b2\n",
    "    z2 = sigmoid(a2)\n",
    "    a3 = np.dot(z2, W3) + b3\n",
    "    y = softmax(a3)\n",
    "    \n",
    "    return y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy:0.9352\n"
     ]
    }
   ],
   "source": [
    "x, t = get_data()\n",
    "network = init_network()\n",
    "\n",
    "accuracy_cnt = 0\n",
    "for i in range(len(x)):\n",
    "    y = predict(network, x[i])\n",
    "    p = np.argmax(y)\n",
    "    if p == t[i]:\n",
    "        accuracy_cnt += 1\n",
    "print(\"Accuracy:\" + str(float(accuracy_cnt) / len(x)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(10000, 784)"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "W1, W2, W3 = network['W1'], network['W2'], network['W3']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((784, 50), (50, 100), (100, 10))"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "W1.shape, W2.shape, W3.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "批处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 0 ns\n",
      "Accuracy:0.9352\n"
     ]
    }
   ],
   "source": [
    "%time\n",
    "batchsize = 100\n",
    "accuracy_cnt = 0\n",
    "\n",
    "for i in range(0, len(x), batchsize):\n",
    "    x_batch = x[i:i + batchsize]\n",
    "    y_batch = predict(network, x_batch)\n",
    "    p = np.argmax(y_batch, axis=1)\n",
    "    accuracy_cnt += np.sum(p == t[i:i + batchsize])\n",
    "print(\"Accuracy:\" + str(float(accuracy_cnt) / len(x)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 神经网络的学习"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 损失函数\n",
    "损失函数，分类问题，t 为目标的独热向量， y 为预测的概率分布\n",
    "   - 均方误差\n",
    "   - 交叉熵误差"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "def mean_squared_error(y, t):\n",
    "    return 0.5 * np.sum((y - t)**2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "def cross_entropy_error(y, t):\n",
    "    \"\"\"\n",
    "    y: 预测得到的每个类别的概率\n",
    "    t: 目标的独热向量\n",
    "    \"\"\"\n",
    "    delta = 1e-7\n",
    "    return -np.sum(t * np.log(y + delta))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "t = np.array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0])\n",
    "y = np.array([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0.510825457099338, 0.09750000000000003)"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cross_entropy_error(y, t), mean_squared_error(y, t)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `mini-batch`学习\n",
    "   - 从训练数据中选择一批数据作为全部数据的近似，对每个 mini-batch 进行学习"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_size = x_train.shape[0]\n",
    "batch_size = 10\n",
    "batch_mask = np.random.choice(train_size, batch_size)\n",
    "x_batch = x_train[batch_mask]\n",
    "t_batch = t_train[batch_mask]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [],
   "source": [
    "def cross_entropy_error(y, t):\n",
    "    if y.ndim == 1:\n",
    "        t = t.reshape(1, t.size)\n",
    "        y = t.reshape(1, y.size)\n",
    "    batch_size = y.shape[0]\n",
    "    return -np.sum(t * np.log(y + 1e-7)) / batch_size"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- t 为目标类别，而不是独热向量时"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [],
   "source": [
    "def cross_entropy_error(y, t):\n",
    "    \"\"\"\n",
    "    y: 每一行预测得到的每个类别的概率\n",
    "    t: 每一行为目标的独热向量，将其转换为类别标签的索引\n",
    "    \"\"\"\n",
    "    if y.ndim == 1:\n",
    "        t = t.reshape(1, t.size)\n",
    "        y = y.reshape(1, y.size)\n",
    "\n",
    "    if t.size == y.size:\n",
    "        t = t.argmax(axis=1)\n",
    "\n",
    "    batch_size = y.shape[0]\n",
    "    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数值微分求得梯度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [],
   "source": [
    "def numerical_gradient(f, x):\n",
    "    h = 1e-4  # 0.0001\n",
    "    grad = np.zeros_like(x)\n",
    "\n",
    "    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])\n",
    "    while not it.finished:\n",
    "        idx = it.multi_index\n",
    "        tmp_val = x[idx]\n",
    "        x[idx] = float(tmp_val) + h\n",
    "        fxh1 = f(x)  # f(x+h)\n",
    "\n",
    "        x[idx] = tmp_val - h\n",
    "        fxh2 = f(x)  # f(x-h)\n",
    "        grad[idx] = (fxh1 - fxh2) / (2 * h)\n",
    "\n",
    "        x[idx] = tmp_val  # 还原值\n",
    "        it.iternext()\n",
    "\n",
    "    return grad"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 梯度下降法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [],
   "source": [
    "def gradient_descent(f, init_x, lr=0.01, step_num=100):\n",
    "    x = init_x\n",
    "\n",
    "    for i in range(step_num):\n",
    "        grad = numerical_gradient(f, x)\n",
    "        x -= lr * grad\n",
    "    return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-5.04890207e-09,  6.73186943e-09])"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def function_2(x):\n",
    "    return x[0]**2 + x[1]**2\n",
    "\n",
    "\n",
    "init_x = np.array([-3.0, 4.0])\n",
    "gradient_descent(function_2, init_x, step_num=1000)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 神经网络的梯度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0.29011245  0.15633975 -0.44645221]\n",
      " [ 0.43516868  0.23450963 -0.66967831]]\n"
     ]
    }
   ],
   "source": [
    "class simpleNet:\n",
    "    def __init__(self):\n",
    "        self.W = np.random.randn(2, 3)\n",
    "\n",
    "    def predict(self, x):\n",
    "        return np.dot(x, self.W)\n",
    "\n",
    "    def loss(self, x, t):\n",
    "        z = self.predict(x)\n",
    "        y = softmax(z)\n",
    "        loss = cross_entropy_error(y, t)\n",
    "\n",
    "        return loss\n",
    "\n",
    "\n",
    "x = np.array([0.6, 0.9])\n",
    "t = np.array([0, 0, 1])\n",
    "\n",
    "net = simpleNet()\n",
    "\n",
    "f = lambda w: net.loss(x, t)\n",
    "dW = numerical_gradient(f, net.W)\n",
    "\n",
    "print(dW)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 神经网络学习算法的实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TwoLayerNet:\n",
    "    def __init__(self,\n",
    "                 input_size,\n",
    "                 hidden_size,\n",
    "                 output_size,\n",
    "                 weight_init_std=0.01):\n",
    "        self.params = {}\n",
    "\n",
    "        self.params['W1'] = weight_init_std * np.random.randn(\n",
    "            input_size, hidden_size)\n",
    "        self.params['b1'] = np.zeros(hidden_size)\n",
    "        self.params['W2'] = weight_init_std * np.random.randn(\n",
    "            hidden_size, output_size)\n",
    "        self.params['b2'] = np.zeros(output_size)\n",
    "\n",
    "    def predict(self, x):\n",
    "        W1, W2 = self.params['W1'], self.params['W2']\n",
    "        b1, b2 = self.params['b1'], self.params['b2']\n",
    "\n",
    "        a1 = np.dot(x, W1) + b1\n",
    "        z1 = sigmoid(a1)\n",
    "        a2 = np.dot(z1, W2) + b2\n",
    "        y = softmax(a2)\n",
    "\n",
    "        return y\n",
    "\n",
    "    def loss(self, x, t):\n",
    "        y = self.predict(x)\n",
    "\n",
    "        return cross_entropy_error(y, t)\n",
    "\n",
    "    def accuracy(self, x, t):\n",
    "        y = self.predict(x)\n",
    "        y = np.argmax(y, axis=1)\n",
    "\n",
    "        t = np.argmax(t, axis=1)\n",
    "\n",
    "        accuracy = np.sum(y == t) / float(x.shape[0])\n",
    "        return accuracy\n",
    "\n",
    "    def numerical_gradient(self, x, t):\n",
    "        loss_W = lambda W: self.loss(x, t)\n",
    "\n",
    "        grads = {}\n",
    "        grads['W1'] = numerical_gradient(loss_W, self.params['W1'])\n",
    "        grads['b1'] = numerical_gradient(loss_W, self.params['b1'])\n",
    "        grads['W2'] = numerical_gradient(loss_W, self.params['W2'])\n",
    "        grads['b2'] = numerical_gradient(loss_W, self.params['b2'])\n",
    "\n",
    "        return grads"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((784, 100), (100,), (100, 10), (10,))"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "net = TwoLayerNet(input_size=784, hidden_size=100, output_size=10)\n",
    "net.params['W1'].shape, net.params['b1'].shape, net.params[\n",
    "    'W2'].shape, net.params['b2'].shape,"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.random.rand(100, 784)\n",
    "y = net.predict(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `mini-batch`的实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 0 ns\n"
     ]
    }
   ],
   "source": [
    "%time\n",
    "(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True,\n",
    "                                                  normalize=True,\n",
    "                                                  one_hot_label=False)\n",
    "train_loss_list = []\n",
    "\n",
    "train_acc_list = []\n",
    "test_acc_list = []\n",
    "iter_per_epoch = max(train_size // batch_size, 1)\n",
    "\n",
    "# 超参数\n",
    "iter_num = 1000\n",
    "train_size = x_train.shape[0]\n",
    "batch_size = 100\n",
    "learning_rate = 0.01\n",
    "\n",
    "network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)\n",
    "\n",
    "for i in range(iter_num):\n",
    "    batch_mask = np.random.choice(train_size, batch_size)\n",
    "    x_batch = x_train[batch_mask]\n",
    "    t_batch = t_train[batch_mask]\n",
    "\n",
    "    grads = network.numerical_gradient(x_batch, t_batch)\n",
    "\n",
    "    for key in ('W1', 'b1', 'W2', 'b2'):\n",
    "        network.params[key] -= learning_rate * grads[key]\n",
    "\n",
    "    loss = network.loss(x_batch, t_batch)\n",
    "    train_loss_list.append(loss)\n",
    "\n",
    "    if i % iter_per_epoch == 0:\n",
    "        train_acc = network.accuracy(x_train, t_train)\n",
    "        test_acc = network.accuracy(x_test, t_test)\n",
    "        train_acc_list.append(train_acc)\n",
    "        test_acc_list.append(test_acc)\n",
    "        print(\"Train acc, Test acc | {}, {}\".format(train_acc, test_acc))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.arange(len(loss))\n",
    "\n",
    "fig = plt.figure(figsize=(8, 4))\n",
    "ax = fig.add_axes([0.1, 0.15, 0.8, 0.8])\n",
    "ax.plot(x, loss, linewidth=2)\n",
    "ax.set_xlabel('$epoch$', fontsize=18)\n",
    "ax.set_ylabel('$loss$', fontsize=18)\n",
    "\n",
    "x0, x1 = 0, 400\n",
    "ax.axvline(x0, ymax=0.3, color=\"grey\", linestyle=\":\")\n",
    "ax.axvline(x1, ymax=0.3, color=\"grey\", linestyle=\":\")\n",
    "\n",
    "ax = fig.add_axes([0.5, 0.5, 0.38, 0.42])\n",
    "x = np.arange(400)\n",
    "ax.plot(x, loss[:400], linewidth=2)\n",
    "ax.set_xlabel('$epoch$', fontsize=14)\n",
    "ax.set_ylabel('$loss$', fontsize=14)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 评价模型性能"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": true
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
